#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__
#include<iostream>
#include<cstring>
#include<memory>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"log.hpp"
#include"InetAddr.hpp"
#define DIE(code) do{exit(code);}while(0)


const static uint16_t DEFAULT_PORT = 8080;
const static std::string DEFAULT_IP = "127.0.0.1";//表示本机地址
class Udp_server
{
public:
    Udp_server(/*const std::string& ip = DEFAULT_IP,*/ uint16_t port = DEFAULT_PORT)
        /*_ip(ip),*/
        // _port(port)
        :_addr(port)    
    {}
    void Init()
    {
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if(_sockfd < 0){
            LOG(log_level::FATAL) << "create socket failed"<<strerror(errno);
            DIE(1);
        }
        LOG(log_level::INFO) << "create socket success fd: "<<_sockfd;
        // struct sockaddr_in addr;//在栈上定义的结构体变量
        // bzero(&addr, sizeof(addr));
        // //memset(&addr, 0, sizeof(addr));
        // //以下是填充这个结构体变量，但并没有写到内核中去
        // addr.sin_family = AF_INET;
        // addr.sin_port = ::htons(_port);//将主机字节序的端口号转换为网络字节序的端口号
        // // addr.sin_addr.s_addr = ::inet_addr(_ip.c_str());//将ip地址字符串转换为网络字节序的32位整数
        // addr.sin_addr.s_addr = INADDR_ANY;//将ip地址设置为INADDR_ANY，表示接收所有地址的消息
        // //以下是将这个结构体变量写入到内核中去（通过bind绑定）
        // int n = ::bind(_sockfd, (struct sockaddr*)&addr, sizeof(addr));
        int n = ::bind(_sockfd, (struct sockaddr*)_addr.GetAddr(), _addr.GetAddrLen());
        if(n < 0){
            LOG(log_level::FATAL) << "bind socket failed"<<strerror(errno);
            DIE(2);
        }
        LOG(log_level::INFO) << "bind socket success";
    }
    void Start()
    {
        _is_running = true; 
        while(true){
            char _recv_buf[1024];
            struct sockaddr_in peer;//定义一个结构体变量来保存对端的地址信息
            socklen_t len = sizeof(peer);//必须设定
            ssize_t n = recvfrom(_sockfd, _recv_buf, sizeof(_recv_buf)-1, 0, (struct sockaddr*)&peer, &len);//采用阻塞式等待 recvfrom函数返回时，表示收到了一个数据报，返回值是收到的数据的长度，如果返回值是-1，表示出错
            if(n > 0){
                _recv_buf[n] = '\0';
                InetAddr client_addr(peer);
                // uint16_t client_port = ntohs(peer.sin_port);//将网络字节序的端口号转换为主机字节序的端口号
                // std::string client_addr = inet_ntoa(peer.sin_addr);//将网络字节序的32位整数转换为ip地址字符串
                // std::string client_info = client_addr + ":"+std::to_string(client_port) + " say: "+_recv_buf;
                std::string client_info = client_addr.GetIp() + ":"+std::to_string(client_addr.GetPort()) + " say: "+_recv_buf;
                LOG(log_level::DEBUG) <<client_info;
                std::string send_msg = "server say: ";
                send_msg += _recv_buf;
                ::sendto(_sockfd, send_msg.c_str(), send_msg.size(), 0, (struct sockaddr*)&peer, len);//服务器发消息
            }
            
        }
        _is_running = false;
    }
    ~Udp_server()
    {   
        if(_sockfd >= 0)
            ::close(_sockfd);
    }
private:
    int _sockfd = -1;
    // uint16_t _port ;//服务器未来的端口号
    // // std::string _ip ;//服务器未来的ip地址
    InetAddr _addr;
    bool _is_running = false;
};


#endif